package neuralNetwork;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import neuralModel.neuron.INeuron;
import neuralModel.neuron.ISignal;
import neuralModel.neuron.Signal;

public class NeuralNetwork implements INeuralNetwork
{
	private Map<String, INeuron> neuronMap;
	private List<List<INeuron>> networkLevelList;
	private List<ISignal> signalList;

	public NeuralNetwork(int levelCount)
	{
		neuronMap = new HashMap<String, INeuron>();
		signalList = new ArrayList<ISignal>();

		networkLevelList = new ArrayList<List<INeuron>>();
		for (int i = 0; i < levelCount; i++)
		{
			networkLevelList.add(new ArrayList<INeuron>());
		}
	}

	@Override
	public Map<String, INeuron> getNeuronMap()
	{
		return neuronMap;
	}

	@Override
	public List<ISignal> getSignalList()
	{
		return signalList;
	}

	@Override
	public void addNeuron(INeuron neuron, int networkLevel)
	{
		if (!neuronMap.containsKey(neuron.getName()))
		{
			addNeuronToLayer(neuron, networkLevel);
			neuronMap.put(neuron.getName(), neuron);
		}
		else
		{
			throw new IllegalArgumentException("Neuron Name Collision");
		}
	}

	private void addNeuronToLayer(INeuron neuron, int layer)
	{
		if (layer >= 0 && layer < networkLevelList.size())
		{
			networkLevelList.get(layer).add(neuron);
			neuron.setNetworkLayer(layer);
		}
		else
		{
			throw new IllegalArgumentException("Invalid Network Layer Specified");
		}
	}

	@Override
	public void removeNeuron(String name)
	{
		INeuron neuron = neuronMap.get(name);
		if (neuron != null)
		{
			removeNeuron(neuron);
		}
		else
		{
			throw new IllegalArgumentException("Invalid Neuron Specified");
		}
	}

	@Override
	public void removeNeuron(INeuron neuron)
	{
		List<INeuron> networkLevel = networkLevelList.get(neuron.getNetworkLayer());
		networkLevel.remove(neuron);
	}

	public INeuron getNeuron(String name)
	{
		return neuronMap.get(name);
	}

	public List<INeuron> getLayer(int networkLevel)
	{
		return networkLevelList.get(networkLevel);
	}

	@Override
	public int getLayerCount()
	{
		return networkLevelList.size();
	}

	@Override
	public void connectNeurons(String sourceName, String targetName, double weight)
	{
		INeuron source = neuronMap.get(sourceName);
		INeuron target = neuronMap.get(targetName);
		if (source != null && target != null)
		{
			connectNeurons(source, target, weight);
		}
		else
		{
			throw new IllegalArgumentException("Invalid Neurons Specified");
		}
	}

	public void connectNeurons(INeuron source, INeuron target, double weight)
	{
		ISignal signal = new Signal(source, target, weight);
		source.addOutputSignal(signal);
		target.addInputSignal(signal);
		signalList.add(signal);
	}

}
